﻿//使用光流法跟踪给定视频或摄像头中的运动特征点

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void main()
{
	const char *fn = "E:\\VC_project\\video\\vtest.avi";
	VideoCapture cap;
	Mat source, result, gray, lastGray;//gray,lastGray对应上一帧和本帧的灰度图
	vector<Point2f>points[2], temp;//对应上一帧和本帧的特征点，上一帧是给定的，本帧时预测结果
	vector<uchar> status;//每一特征点检测状态,光流得到标定的特征点位置改变怎为1，否则为0
	vector<float> err;//每一特征点计算误差

	cap.open(fn);
	if (!cap.isOpened())
	{
		cout << "无法打开视频！" << endl;
		return;
	}

	for (;;)
	{
		cap >> source;
		if (source.empty())
			break;

		cvtColor(source, gray, COLOR_BGR2GRAY);

		//以下是特征点处理
		if (points[0].size() < 10)//如果特征点数太少，重新检测特征点
		{
			goodFeaturesToTrack(gray, points[0], 255, 0.01, 20);

		}

		if (lastGray.empty())
		{
			gray.copyTo(lastGray);
		}

		//计算光流
		calcOpticalFlowPyrLK(lastGray, gray, points[0], points[1], status, err);

		//下面是删除误判点
		int counter = 0;
		for (int i = 0; i < points[1].size(); i++)
		{
			double dist = norm(points[1][i] - points[0][i]);//本帧和上一帧特征点的距离
			if (status[i] && dist > 2.0&&dist <= 20.0)//合理特征点的追踪
			{
				points[0][counter] = points[0][i];
				points[1][counter++] = points[1][i];
			}
		}

		points[0].resize(counter); //改变容器大小
		points[1].resize(counter);

		//显示特征点和运动轨迹
		source.copyTo(result);

		for (int i = 0; i < points[1].size(); i++)
		{
			line(result, points[0][i], points[1][i], Scalar(0, 255, 0));
			circle(result, points[1][i], 2, Scalar(0, 255, 0));
		}

		swap(points[0], points[1]);
		swap(lastGray, gray);

		imshow("原图像", result);
		imshow("光流估计结果", result);

		char key = waitKey(10);
		if(key ==27)
		{
			break;
		}
	}

	waitKey();
}

